package wallet

import (
	"context"
	"database/sql"
	"fmt"
	"github.com/zeromicro/go-zero/core/stores/cache"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
	"navi-mumbai/common/gensql"
	"navi-mumbai/common/key/walletkey"
	"time"
)

var _ UserGameOrderFlowModel = (*customUserGameOrderFlowModel)(nil)

type (
	// UserGameOrderFlowModel is an interface to be customized, add more methods here,
	// and implement the added methods in customUserGameOrderFlowModel.
	UserGameOrderFlowModel interface {
		userGameOrderFlowModel
		InsertTrans(ctx context.Context, tx sqlx.Session, data *UserGameOrderFlow) (sql.Result, error)
		InsertGameOrderFlow(ctx context.Context, data *UserGameOrderFlow) (sql.Result, error)
		UpdateStateTrans(ctx context.Context, tx sqlx.Session, flowNo int64, state int64) error
		UpdateCashOutTrans(ctx context.Context, tx sqlx.Session, flowNo int64, state int64, cashOutAmount int64) error
		Find(ctx context.Context, gameId, uid, providerId, moneyType int64, start, end *time.Time, pageNo, pageSize int64) ([]*UserGameOrderFlow, error)

		CountOrderCount(ctx context.Context, uid, providerId, gameId, moneyType, state int64, start, end *time.Time) (int64, error)
		SumOrderAmount(ctx context.Context, providerId, gameId int64, start, end *time.Time) (int64, error)
		SumReturnAmount(ctx context.Context, providerId, gameId int64, start, end *time.Time) (int64, error)
		CountReturnOrderCount(ctx context.Context, uid, providerId, gameId, moneyType int64, start, end *time.Time) (int64, error)
		CountUser(ctx context.Context, providerId, gameId int64, start, end *time.Time) (int64, error)
		CountReturnUser(ctx context.Context, providerId, gameId int64, start, end *time.Time) (int64, error)

		CountNewUserOrder(ctx context.Context, start, end *time.Time, startUid, endUid int64) (int64, error)
		CountNewUserReturn(ctx context.Context, start, end *time.Time, startUid, endUid int64) (int64, error)
		SumNewUserOrderAmount(ctx context.Context, start, end *time.Time, startUid, endUid int64) (int64, error)
		SumNewUserReturnAmount(ctx context.Context, start, end *time.Time, startUid, endUid int64) (int64, error)

		CountUserOrder(ctx context.Context, start, end *time.Time) (int64, error)
		CountUserReturn(ctx context.Context, start, end *time.Time) (int64, error)
		SumUserOrderAmount(ctx context.Context, start, end *time.Time) (int64, error)
		SumUserReturnAmount(ctx context.Context, start, end *time.Time) (int64, error)
	}

	customUserGameOrderFlowModel struct {
		*defaultUserGameOrderFlowModel
		genSql *gensql.GenSql
	}
)

// NewUserGameOrderFlowModel returns a model for the database table.
func NewUserGameOrderFlowModel(conn sqlx.SqlConn, c cache.CacheConf, opts ...cache.Option) UserGameOrderFlowModel {
	return &customUserGameOrderFlowModel{
		defaultUserGameOrderFlowModel: newUserGameOrderFlowModel(conn, c, opts...),
		genSql:                        gensql.NewGenSql(),
	}
}

func (m *customUserGameOrderFlowModel) InsertGameOrderFlow(ctx context.Context, data *UserGameOrderFlow) (sql.Result, error) {
	mumbaiWalletUserGameOrderFlowExternalFlowNoKey := fmt.Sprintf("%s%v", cacheMumbaiWalletUserGameOrderFlowExternalFlowNoPrefix, data.ExternalFlowNo)
	mumbaiWalletUserGameOrderFlowFlowNoKey := fmt.Sprintf("%s%v", cacheMumbaiWalletUserGameOrderFlowFlowNoPrefix, data.FlowNo)
	ret, err := m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
		query := fmt.Sprintf("insert ignore into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, userGameOrderFlowRowsExpectAutoSet)
		return conn.ExecCtx(ctx, query, data.FlowNo, data.ExternalFlowNo, data.MoneyType, data.MoneyAmount, data.GameId, data.ProviderId, data.ReturnAmount, data.Uid, data.State, data.OrderTime, data.Multiplier)
	}, mumbaiWalletUserGameOrderFlowExternalFlowNoKey, mumbaiWalletUserGameOrderFlowFlowNoKey)
	return ret, err
}

func (m *customUserGameOrderFlowModel) InsertTrans(ctx context.Context, tx sqlx.Session, data *UserGameOrderFlow) (sql.Result, error) {
	query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, userGameOrderFlowRowsExpectAutoSet)
	ret, err := tx.ExecCtx(ctx, query, data.FlowNo, data.ExternalFlowNo, data.MoneyType, data.MoneyAmount, data.GameId, data.ProviderId, data.ReturnAmount, data.Uid, data.State, data.OrderTime, data.Multiplier)
	return ret, err
}

func (m *customUserGameOrderFlowModel) UpdateStateTrans(ctx context.Context, tx sqlx.Session, flowNo int64, state int64) error {
	query := fmt.Sprintf("update %s set state = ? where flow_no = ?", m.table)
	_, err := tx.ExecCtx(ctx, query, state, flowNo)
	if err != nil {
		return err
	}
	return nil
}

func (m *customUserGameOrderFlowModel) UpdateCashOutTrans(ctx context.Context, tx sqlx.Session, flowNo int64, state int64, cashOutAmount int64) error {
	query := fmt.Sprintf("update %s set state = ?, return_amount = ? where flow_no = ?", m.table)
	_, err := tx.ExecCtx(ctx, query, state, cashOutAmount, flowNo)
	if err != nil {
		return err
	}
	return nil
}

func (m *customUserGameOrderFlowModel) Find(ctx context.Context, gameId, uid, providerId, moneyType int64, start, end *time.Time, pageNo, pageSize int64) ([]*UserGameOrderFlow, error) {
	query := fmt.Sprintf("select %s from %s ", userGameOrderFlowRows, m.table)
	m.genSql.InitSql(query)

	if start != nil {
		m.genSql = m.genSql.Where("order_time >= ?", start)
	}
	if end != nil {
		m.genSql = m.genSql.Where("order_time <= ?", end)
	}
	if gameId != 0 {
		m.genSql = m.genSql.Where("game_id = ?", gameId)
	} else {
		m.genSql = m.genSql.Where("game_id != 0")
	}
	if uid != 0 {
		m.genSql = m.genSql.Where("uid = ?", uid)
	} else {
		m.genSql = m.genSql.Where("uid != 0")
	}
	if providerId != 0 {
		m.genSql = m.genSql.Where("provider_id = ?", providerId)
	} else {
		m.genSql = m.genSql.Where("provider_id != 0")
	}
	if moneyType != 0 {
		m.genSql = m.genSql.Where("money_type = ?", moneyType)
	} else {
		m.genSql = m.genSql.Where("money_type != 0")
	}

	// 分页
	if pageNo < 1 {
		pageNo = 1
	}
	if pageSize <= 0 {
		pageSize = 10
	}
	query, values, err := m.genSql.OrderBy("create_time DESC").Limit(uint64(pageSize)).Offset(uint64((pageNo - 1) * pageSize)).ToSql()
	if err != nil {
		return nil, err
	}

	resp := make([]*UserGameOrderFlow, 0)
	err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...)
	switch err {
	case nil:
		return resp, nil
	default:
		return nil, err
	}
}

func (m *customUserGameOrderFlowModel) CountOrderCount(ctx context.Context, uid, providerId, gameId, moneyType, state int64, start, end *time.Time) (int64, error) {
	q := fmt.Sprintf("select count(flow_no) from %s ", m.table)
	m.genSql.InitSql(q)

	if start != nil {
		m.genSql = m.genSql.Where("order_time >= ?", start)
	}
	if end != nil {
		m.genSql = m.genSql.Where("order_time <= ?", end)
	}
	if gameId != 0 {
		m.genSql = m.genSql.Where("game_id = ?", gameId)
	}
	if uid != 0 {
		m.genSql = m.genSql.Where("uid = ?", uid)
	}
	if providerId != 0 {
		m.genSql = m.genSql.Where("provider_id = ?", providerId)
	}
	if moneyType != 0 {
		m.genSql = m.genSql.Where("money_type = ?", moneyType)
	}
	if state != 0 {
		m.genSql = m.genSql.Where("state = ?", state)
	}

	query, values, err := m.genSql.ToSql()
	if err != nil {
		return 0, err
	}
	fmt.Println("CountOrderCount ==== query : : ", query)
	var resp int64
	err = m.QueryRowNoCacheCtx(ctx, &resp, query, values...)
	switch err {
	case nil:
		return resp, nil
	default:
		fmt.Println("CountOrderCount ==== err : : ", err)
		return 0, err
	}
}

func (m *customUserGameOrderFlowModel) CountReturnOrderCount(ctx context.Context, uid, providerId, gameId, moneyType int64, start, end *time.Time) (int64, error) {
	q := fmt.Sprintf("select count(flow_no) from %s ", m.table)
	m.genSql.InitSql(q)

	if start != nil {
		m.genSql = m.genSql.Where("order_time >= ?", start)
	}
	if end != nil {
		m.genSql = m.genSql.Where("order_time <= ?", end)
	}
	if gameId != 0 {
		m.genSql = m.genSql.Where("game_id = ?", gameId)
	}
	if uid != 0 {
		m.genSql = m.genSql.Where("uid = ?", uid)
	}
	if providerId != 0 {
		m.genSql = m.genSql.Where("provider_id = ?", providerId)
	}
	if moneyType != 0 {
		m.genSql = m.genSql.Where("money_type = ?", moneyType)
	}
	m.genSql = m.genSql.Where("state = ?", walletkey.GameOrderStateSuccess).Where("return_amount > 0")

	query, values, err := m.genSql.ToSql()
	if err != nil {
		return 0, err
	}

	var resp int64
	err = m.QueryRowNoCacheCtx(ctx, &resp, query, values...)
	switch err {
	case nil:
		return resp, nil
	default:
		return 0, err
	}
}

func (m *customUserGameOrderFlowModel) SumOrderAmount(ctx context.Context, providerId, gameId int64, start, end *time.Time) (int64, error) {
	q := fmt.Sprintf("select coalesce(sum(money_amount), 0) from %s ", m.table)
	m.genSql.InitSql(q)

	if start != nil {
		m.genSql = m.genSql.Where("order_time >= ?", start)
	}
	if end != nil {
		m.genSql = m.genSql.Where("order_time <= ?", end)
	}
	if providerId != 0 {
		m.genSql = m.genSql.Where("provider_id = ?", providerId)
	}
	if gameId != 0 {
		m.genSql = m.genSql.Where("game_id = ?", gameId)
	}

	m.genSql = m.genSql.Where("state = ?", walletkey.GameOrderStateSuccess)
	query, args, err := m.genSql.ToSql()
	if err != nil {
		return 0, err
	}
	fmt.Println("SumOrderAmount ===== , query: %", query)
	var resp int64
	err = m.QueryRowNoCacheCtx(ctx, &resp, query, args...)
	switch err {
	case nil:
		return resp, nil
	default:
		return 0, err
	}
}

func (m *customUserGameOrderFlowModel) SumReturnAmount(ctx context.Context, providerId, gameId int64, start, end *time.Time) (int64, error) {
	q := fmt.Sprintf("select coalesce(sum(return_amount), 0) from %s ", m.table)
	m.genSql.InitSql(q)

	if start != nil {
		m.genSql = m.genSql.Where("order_time >= ?", start)
	}
	if end != nil {
		m.genSql = m.genSql.Where("order_time <= ?", end)
	}
	if providerId != 0 {
		m.genSql = m.genSql.Where("provider_id = ?", providerId)
	}
	if gameId != 0 {
		m.genSql = m.genSql.Where("game_id = ?", gameId)
	}
	m.genSql = m.genSql.Where("state = ?", walletkey.GameOrderStateSuccess).Where("return_amount > 0")
	query, args, err := m.genSql.ToSql()
	if err != nil {
		return 0, err
	}
	var resp int64
	err = m.QueryRowNoCacheCtx(ctx, &resp, query, args...)
	switch err {
	case nil:
		return resp, nil
	default:
		return 0, err
	}
}

const countGameOrderUserSql = "select count(uid) from (select uid from %s where order_time between ? and ? and state = ? and provider_id = ? and game_id = ? group by uid having count(uid) >= 1) t"

func (m *customUserGameOrderFlowModel) CountUser(ctx context.Context, providerId, gameId int64, start, end *time.Time) (int64, error) {
	var cnt int64
	var err error
	query := fmt.Sprintf(countGameOrderUserSql, m.table)
	err = m.QueryRowNoCacheCtx(ctx, &cnt, query, start, end, walletkey.GameOrderStateSuccess, providerId, gameId)
	switch err {
	case nil:
		return cnt, nil
	default:
		return 0, err
	}
}

const countGameOrderReturnUserSql = "select count(uid) from (select uid from %s where order_time between ? and ? and state = ? and return_amount > 0 and provider_id = ? and game_id = ? group by uid having count(uid) >= 1) t"

func (m *customUserGameOrderFlowModel) CountReturnUser(ctx context.Context, providerId, gameId int64, start, end *time.Time) (int64, error) {
	var cnt int64
	var err error
	query := fmt.Sprintf(countGameOrderReturnUserSql, m.table)
	err = m.QueryRowNoCacheCtx(ctx, &cnt, query, start, end, walletkey.GameOrderStateSuccess, providerId, gameId)
	switch err {
	case nil:
		return cnt, nil
	default:
		return 0, err
	}
}

const countGameOrderNewUserSql = "select count(uid) from (select uid from %s where order_time between ? and ? and state = ? and uid between ? and ? group by uid having count(uid) >= 1) t"

func (m *customUserGameOrderFlowModel) CountNewUserOrder(ctx context.Context, start, end *time.Time, startUid, endUid int64) (int64, error) {
	var cnt int64
	var err error
	query := fmt.Sprintf(countGameOrderNewUserSql, m.table)
	err = m.QueryRowNoCacheCtx(ctx, &cnt, query, start, end, walletkey.GameOrderStateSuccess, startUid, endUid)
	switch err {
	case nil:
		return cnt, nil
	default:
		return 0, err
	}
}

const countGameOrderReturnNewUserSql = "select count(uid) from (select uid from %s where order_time between ? and ? and state = ? and return_amount > 0 and uid between ? and ? group by uid having count(uid) >= 1) t"

func (m *customUserGameOrderFlowModel) CountNewUserReturn(ctx context.Context, start, end *time.Time, startUid, endUid int64) (int64, error) {
	var cnt int64
	var err error
	query := fmt.Sprintf(countGameOrderReturnNewUserSql, m.table)
	err = m.QueryRowNoCacheCtx(ctx, &cnt, query, start, end, walletkey.GameOrderStateSuccess, startUid, endUid)
	switch err {
	case nil:
		return cnt, nil
	default:
		return 0, err
	}
}
func (m *customUserGameOrderFlowModel) SumNewUserOrderAmount(ctx context.Context, start, end *time.Time, startUid, endUid int64) (int64, error) {
	q := fmt.Sprintf("select coalesce(sum(money_amount), 0) from %s ", m.table)
	m.genSql.InitSql(q)

	if start != nil {
		m.genSql = m.genSql.Where("order_time >= ?", start)
	}
	if end != nil {
		m.genSql = m.genSql.Where("order_time <= ?", end)
	}
	if startUid != 0 {
		m.genSql = m.genSql.Where("uid >= ?", startUid)
	}
	if endUid != 0 {
		m.genSql = m.genSql.Where("uid <= ?", endUid)
	}
	m.genSql = m.genSql.Where("state = ?", walletkey.GameOrderStateSuccess)
	query, args, err := m.genSql.ToSql()
	if err != nil {
		return 0, err
	}
	var resp int64
	err = m.QueryRowNoCacheCtx(ctx, &resp, query, args...)
	switch err {
	case nil:
		return resp, nil
	default:
		return 0, err
	}
}
func (m *customUserGameOrderFlowModel) SumNewUserReturnAmount(ctx context.Context, start, end *time.Time, startUid, endUid int64) (int64, error) {
	q := fmt.Sprintf("select coalesce(sum(return_amount), 0) from %s ", m.table)
	m.genSql.InitSql(q)

	if start != nil {
		m.genSql = m.genSql.Where("order_time >= ?", start)
	}
	if end != nil {
		m.genSql = m.genSql.Where("order_time <= ?", end)
	}
	if startUid != 0 {
		m.genSql = m.genSql.Where("uid >= ?", startUid)
	}
	if endUid != 0 {
		m.genSql = m.genSql.Where("uid <= ?", endUid)
	}
	m.genSql = m.genSql.Where("state = ?", walletkey.GameOrderStateSuccess).Where("return_amount > 0")
	query, args, err := m.genSql.ToSql()
	if err != nil {
		return 0, err
	}
	var resp int64
	err = m.QueryRowNoCacheCtx(ctx, &resp, query, args...)
	switch err {
	case nil:
		return resp, nil
	default:
		return 0, err
	}
}

const countGameOrderUserSql2 = "select count(uid) from (select uid from %s where order_time between ? and ? and state = ? group by uid having count(uid) >= 1) t"

func (m *customUserGameOrderFlowModel) CountUserOrder(ctx context.Context, start, end *time.Time) (int64, error) {
	var cnt int64
	var err error
	query := fmt.Sprintf(countGameOrderUserSql2, m.table)
	err = m.QueryRowNoCacheCtx(ctx, &cnt, query, start, end, walletkey.GameOrderStateSuccess)
	switch err {
	case nil:
		return cnt, nil
	default:
		return 0, err
	}
}

const countGameOrderReturnUserSql2 = "select count(uid) from (select uid from %s where order_time between ? and ? and state = ? and return_amount > 0 group by uid having count(uid) >= 1) t"

func (m *customUserGameOrderFlowModel) CountUserReturn(ctx context.Context, start, end *time.Time) (int64, error) {
	var cnt int64
	var err error
	query := fmt.Sprintf(countGameOrderReturnUserSql2, m.table)
	err = m.QueryRowNoCacheCtx(ctx, &cnt, query, start, end, walletkey.GameOrderStateSuccess)
	switch err {
	case nil:
		return cnt, nil
	default:
		return 0, err
	}
}
func (m *customUserGameOrderFlowModel) SumUserOrderAmount(ctx context.Context, start, end *time.Time) (int64, error) {
	q := fmt.Sprintf("select coalesce(sum(money_amount), 0) from %s ", m.table)
	m.genSql.InitSql(q)
	if start != nil {
		m.genSql = m.genSql.Where("order_time >= ?", start)
	}
	if end != nil {
		m.genSql = m.genSql.Where("order_time <= ?", end)
	}
	m.genSql = m.genSql.Where("state = ?", walletkey.GameOrderStateSuccess)
	query, args, err := m.genSql.ToSql()
	if err != nil {
		return 0, err
	}
	var resp int64
	err = m.QueryRowNoCacheCtx(ctx, &resp, query, args...)
	switch err {
	case nil:
		return resp, nil
	default:
		return 0, err
	}
}

func (m *customUserGameOrderFlowModel) SumUserReturnAmount(ctx context.Context, start, end *time.Time) (int64, error) {
	q := fmt.Sprintf("select coalesce(sum(return_amount), 0) from %s ", m.table)
	m.genSql.InitSql(q)

	if start != nil {
		m.genSql = m.genSql.Where("order_time >= ?", start)
	}
	if end != nil {
		m.genSql = m.genSql.Where("order_time <= ?", end)
	}

	m.genSql = m.genSql.Where("state = ?", walletkey.GameOrderStateSuccess).Where("return_amount > 0")
	query, args, err := m.genSql.ToSql()
	if err != nil {
		return 0, err
	}

	var resp int64
	err = m.QueryRowNoCacheCtx(ctx, &resp, query, args...)
	switch err {
	case nil:
		return resp, nil
	default:
		return 0, err
	}
}
